"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
var MVVM = /** @class */ (function () {
    function MVVM(options) {
        this.$el = options.el;
        this.$data = options.data;
        if (this.$el) {
            //数据劫持
            new Observer(this.$data);
            //编译模板+数据
            new Compile(this.$el, this);
        }
    }
    return MVVM;
}());
var Dep = /** @class */ (function () {
    function Dep() {
        this.Watchers = [];
    }
    Dep.prototype.add = function (watcher) {
        this.Watchers.push(watcher);
    };
    Dep.prototype.notify = function () {
        this.Watchers.forEach(function (watcher) {
            watcher.updata();
        });
    };
    return Dep;
}());
//观察者
var Watcher = /** @class */ (function () {
    // Dep.target:any
    function Watcher(vm, expr, cb) {
        this.vm = vm;
        this.expr = expr;
        this.cb = cb;
        this.oldVal = this.get();
    }
    Watcher.prototype.get = function () {
        Dep.target = this;
        var value = compileUtil.getVal(this.expr, this.vm);
        Dep.target = null;
        return value;
    };
    Watcher.prototype.updata = function () {
        var newVal = compileUtil.getVal(this.expr, this.vm);
        if (newVal != this.oldVal) {
            this.cb(newVal);
        }
    };
    return Watcher;
}());
//数据劫持
var Observer = /** @class */ (function () {
    function Observer(data) {
        this.observer(data);
    }
    Observer.prototype.observer = function (data) {
        //判断data是否存在
        if (data && typeof data === 'object') {
            for (var key in data) {
                this.observerData(data, key, data[key]);
            }
        }
    };
    Observer.prototype.observerData = function (data, key, value) {
        this.observer(value);
        //实例观察
        var dep = new Dep();
        Object.defineProperty(data, key, {
            set: function (newVal) {
                console.log('设置值');
                if (value != newVal) { //值改变
                    value = newVal;
                }
            },
            get: function () {
                Dep.target && dep.add(Dep.target);
                console.log('获取值');
                return value;
            }
        });
    };
    return Observer;
}());
//编译
var Compile = /** @class */ (function () {
    function Compile(el, vm) {
        this.vm = vm;
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        //把html节点放到内存中
        var fragment = this.nodeToElement(this.el);
        //存到文档片段之后进行编译
        this.compile(fragment);
    }
    Compile.prototype.isElementNode = function (node) {
        return node.nodeType === 1;
    };
    Compile.prototype.nodeToElement = function (node) {
        //创建一个空白文档
        var fragment = document.createDocumentFragment();
        var firstChild;
        while (firstChild = node.firstChild) {
            fragment.appendChild(firstChild);
        }
        return fragment;
    };
    Compile.prototype.compile = function (node) {
        var _this = this;
        //拿到模板的所有子节点
        var ChildNodes = node.ChildNodes;
        //子节点循环
        __spreadArrays(ChildNodes).forEach(function (item) {
            if (_this.isElementNode(item)) { //是元素节点
                _this.compileElement(item);
                _this.compile(item);
            }
            else {
                _this.compileText(item);
            }
        });
    };
    Compile.prototype.isDirective = function (node) {
        return node.startsWith('v-');
    };
    Compile.prototype.compileElement = function (node) {
        var _this = this;
        //拿到元素的属性
        var attributes = node.attributes;
        __spreadArrays(attributes).forEach(function (attr) {
            var name = attr.name, value = attr.value, expr = attr.expr;
            if (_this.isDirective(name)) {
                var _a = name.split('-'), directive = _a[1];
                compileUtil[directive](node, expr, _this.vm);
            }
        });
    };
    Compile.prototype.compileText = function (node) {
        //文本节点的内容
        var content = node.textContent;
        //判断是否含有{{}}
        if (/\{\{(.+?)\}\}/.test(content)) {
            compileUtil.content(node, content, this.vm);
        }
    };
    return Compile;
}());
var compileUtil = {
    getVal: function (expr, vm) {
        return expr.split('.').reduce(function (pre, current) {
            return pre[current];
        }, vm.$data);
    },
    setVal: function (vm, expr, value) {
        expr.split('.').reduce(function (data, current, index, arr) {
            if (index === arr.length - 1) {
                data[current] = value;
            }
            return data[current];
        }, vm.$data);
    },
    //从vm.$data中拿到 user.name的值  给node节点value 的值
    model: function (node, expr, vm) {
        var _this = this;
        //拿值
        var value = this.getVal(expr, vm);
        //node.value = value;
        var fn = this.updater.compileModel;
        new Watcher(vm, expr, function (newVal) {
            fn(node, newVal);
        });
        fn(node, value);
        node.addEventListener('input', function (e) {
            _this.setVal(vm, expr, e.target.value);
        });
    },
    content: function (node, content, vm) {
        var _this = this;
        var value = content.replace(/\{\{(.+?)\}\}/g, function () {
            var argv = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                argv[_i] = arguments[_i];
            }
            new Watcher(vm, argv[1], function (newVal) {
                fn(node, newVal);
            });
            return _this.getVal(argv[1], vm);
        });
        var fn = this.updater.compileContent;
        fn(node, value);
    },
    //text
    text: function (node, expr, vm) {
        //拿值
        var value = this.getVal(expr, vm);
        //node.value = value;
        var fn = this.updater.compiletexth;
        new Watcher(vm, expr, function (newVal) {
            fn(node, newVal);
        });
        fn(node, value);
    },
    html: function (node, expr, vm) {
        //拿值
        var value = this.getVal(expr, vm);
        //node.value = value;
        var fn = this.updater.compiletexth;
        new Watcher(vm, expr, function (newVal) {
            fn(node, newVal);
        });
        fn(node, value);
    },
    updater: {
        compileModel: function (node, value) {
            node.value = value;
        },
        compiletexth: function (node, value) {
            node.innerHtml = value;
        },
        compileContent: function (node, value) {
            node.textContent = value;
        }
    }
};
